#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>

#define MAX_LISTEN_QUE	13
#define MAXEVENTSIZE 512
#define BUFF "hello client , i'm server!"
//初始化并返回套接字函数，socket、bind、listen
int socket_init(void)
{
    int ser_fd = -1;
    int rv = -1;
    int on = 1;
    int port = 9998;
    struct sockaddr_in ser_addr;
    ser_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(ser_fd < 0) {
        printf("create socket failure:%s\n", strerror(errno));
        return -1;
    }
    printf("\ncreate socket[%d]successfully!\n", ser_fd);
    if((rv = setsockopt(ser_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
        printf("\n设置地址重用失败:%s\n", strerror(errno));
        return -1;
    }
    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(port);
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    rv = bind(ser_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
    if(rv < 0) {
        printf("ser_fd[%d]bind port[%d]failure:%s\n", ser_fd, port, strerror(errno));
        return -1;
    }
    printf("\nser_fd[%d]bind port[%d]successfully!\n", ser_fd, port);
    rv = listen(ser_fd, MAX_LISTEN_QUE);
    if(rv < 0) {
        printf("\nser_fd[%dlisten port[%d]failure:%s\n", ser_fd, port, strerror(errno));
        return -1;
    }
    printf("\nser_fd[%dlisten port[%d]successfully!\n", ser_fd, port);
    return ser_fd;
}


int main(int argc, char **argv)
{
    int listenfd = socket_init();
    int epollfd;
    int rv, num, connfd;
    struct epoll_event event;
    struct epoll_event events_array[MAXEVENTSIZE];
    struct sockaddr_in cliaddr;
    char buff[1024] = {};
    socklen_t len;
    epollfd = epoll_create(111);//创建一个新的epoll实例(描述符)，其对应的兴趣列表初始化为空。
    if((epollfd = epoll_create(111)) < 0) {
        printf("epoll_create failure:%s\n", strerror(errno));
        return -1;
    }
    printf("epoll_create [%d] successfully!\n", epollfd);
    event.events =  EPOLLIN;
    event.data.fd = listenfd;
    rv = epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd,  &event);
    if(rv < 0) {
        printf("epoll_trl failure:%s\n", strerror(errno));
        close(epollfd);
        return -1;
    }
    while(1) {
        num = epoll_wait(epollfd, events_array, MAXEVENTSIZE, -1);
        if(num < 0) {
            printf("epoll_wait failure:%s\n", strerror(errno));
            close(epollfd);
            return -1;
        }
        else if(num == 0) {
            printf("eopll_wait timeout!\n");
            close(epollfd);
            continue;
        }
        printf("num %d\n", num);
        for(int i = 0; i < num; i++) {
            if(events_array[i].events == EPOLLIN && events_array[i].data.fd == listenfd) {
                connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
                if(connfd < 0) {
                    printf("accpet new client failure:%s\n", strerror(errno));
                    continue;
                }
                printf("accpet new client[%d] successfully\n", connfd);
                //将新连接进来的客户端注册到epollfd中
                event.events = EPOLLIN;
                event.data.fd = connfd;
                rv = epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &event);
                if(rv == 0) {
                    printf("add new connfd[%d] to epollfd successfully!\n", connfd);
                }
                else if(rv < 0) {
                    printf("add new connfd[%d] to epollfd failure:%s\n", connfd, strerror(errno));
                    close(connfd);
                    continue;
                }
            }
            else {
                memset(buff, 0, sizeof(buff));
                rv = read(events_array[i].data.fd, buff, sizeof(buff));
                if(rv <= 0) {
                    if(0 == rv) {
                        printf("client[%d] get disconnetion!\n", events_array[i].data.fd);
                    }else{
                        printf("read data from client[%d]failure:%s\n", events_array[i].data.fd, strerror(errno));
                    }
                    close(events_array[i].data.fd);
                    continue;
                }
                printf("read [%d]: %s\n", events_array[i].data.fd, buff);
        }   }
    }
    close(listenfd);
}

